HDU 5644 King's Pilots 费用流

King's Pilots

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=5644

Description

The military parade will last for n days. There is a aerobatic flight shows everyday during the parade. On the ith day , Pi pilots are required. But the pilots are not willing to work continually without an extra salary for even two days , because they are extremely tired.

There are m Holiday formulations in this country. For each formulation j , that is: when a pilot works on a day , if you pay him Sj dollars he is willing to come back Tj days after that day.

For example , If a pilot work on the rth day , and Tj==1 then he will return to work on r+1th day

At the very beginning there are k pilots , but of course you can hire more pilots. However , training new pilots require P days and for each new pilot you need pay him Q dollars. (Which means you can only use new pilots on Pth day or later)

Now our great king needs you to plan all these things. There must be enough pilots everyday and the cost must be minimized. Please tell the king what is the lowest cost;

The N - 1 round, the next person of the person who is out in the last round counts off, and the person who report number n−1 is out.

And the last man is survivor. Do you know the label of the survivor?

Input

The first line contains a number T(T≤5), the number of testcases.

For each testcase, the first line contains a number n(n≤200)

On the second line , there are n numbers Pi(1≤i≤n) indicating the number of pilots needed on that day

On the third line , 3 numbers , m(1≤m≤5),P,Q

On the following m lines , each line has two numbers: Si , Ti

all input data x satisfy x∈[0,200]

Output

For each testcase, print a single number. The minimum cost.

If there is no solution , just put No solution

Sample Input

1
5 10
1 3 5 10 6
1 3 5
2 2

Sample Output

48

Hint

题意

有n天,每天需要p[i]个人,你一开始雇佣了k个人

你从第p天开始可以再花Q元雇佣一个人。

然后这些人只会工作一天。

但是有m种政策,可以使得这些人在休息t[i]天后只用花s[i]元就可以再让这些工人工作了。

题解:

费用流。

建图的话建两层。

第一层假装没有那m种政策,然后无脑建图就好了。

S向1连容量为k,花费为0的边。

每个点向T连容量为P[i],花费为0的边。

每个点i向i+1连容量为inf,花费为0的边。

然后P天后的,连容量为inf,花费为q的边。

第二层连政策。

S向每个点连容量为P[i],花费为0的边。

每个点向T[i]天后的第一层的点连容量为inf,花费为S[i]

每个点i向i+1连容量为inf,花费为0的边。

一层维护工作,一层维护政策。

然后check是否满流就好了。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to, next, cap, flow, cost;
    int x, y;
} edge[MAXM],HH[MAXN],MM[MAXN];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N, M;
char map[MAXN][MAXN];
void init()
{
    N = MAXN;
    tol = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)//左端点,右端点,容量,花费
{
    edge[tol]. to = v;
    edge[tol]. cap = cap;
    edge[tol]. cost = cost;
    edge[tol]. flow = 0;
    edge[tol]. next = head[u];
    head[u] = tol++;
    edge[tol]. to = u;
    edge[tol]. cap = 0;
    edge[tol]. cost = -cost;
    edge[tol]. flow = 0;
    edge[tol]. next = head[v];
    head[v] = tol++;
}
bool spfa(int s, int t)
{
    queue<int>q;
    for(int i = 0; i < N; i++)
    {
        dis[i] = INF;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i]. next)
        {
            int v = edge[i]. to;
            if(edge[i]. cap > edge[i]. flow &&
                    dis[v] > dis[u] + edge[i]. cost )
            {
                dis[v] = dis[u] + edge[i]. cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1) return false;
    else return true;
}
//返回的是最大流, cost存的是最小费用
int minCostMaxflow(int s, int t, int &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
        {
            if(Min > edge[i]. cap - edge[i]. flow)
                Min = edge[i]. cap - edge[i]. flow;
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
        {
            edge[i]. flow += Min;
            edge[i^1]. flow -= Min;
            cost += edge[i]. cost * Min;
        }
        flow += Min;
    }
    return flow;
}
const int inf = 1e9;
int P[205],p,q,S[205],T[205];
void solve()
{
    init();
    int m,n,k,sum=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&P[i]),sum+=P[i];
    scanf("%d%d%d",&m,&p,&q);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&S[i],&T[i]);
    int st=5000,ed=5001;
    for(int i=1;i<=n;i++)
    {
        addedge(st,i,P[i],0);
        addedge(n+i,ed,P[i],0);
    }
    addedge(st,n+1,k,0);
    for(int i=p;i<=n;i++)
        addedge(st,n+i,inf,q);
    for(int i=1;i<n;i++)
        addedge(i,i+1,inf,0);
    for(int i=1;i<n;i++)
        addedge(n+i,n+i+1,inf,0);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            if(i+T[j]<=n)
                addedge(i,n+i+T[j],inf,S[j]);
    }
    int ans1=0,ans2=0;
    ans1=minCostMaxflow(st,ed,ans2);
    if(ans1==sum)printf("%d\n",ans2);
    else printf("No solution\n");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)solve();
    return 0;
}
posted @ 2016-03-12 23:10  qscqesze  阅读(338)  评论(0编辑  收藏  举报